#pragma once

#include "U7FileDefs.h"
#include "Graphic.h"

void GetShapeFrameInfo(
	const SHAPEENTRY* shapeEntry,
	long shapeLength,
	int frameIndex,
	U7VECTOR2& hotspot,
	U7VECTOR2& dimension );

void DrawShapeTile(
	PGRAPHIC pGraphic,
	const TILE tile,
	int anchorX,
	int anchorY );

void DrawShapeFrame(
	PGRAPHIC pGraphic,
	const FRAMEENTRY* frameEntry,
	int anchorX,
	int anchorY );

void DrawShapeFrame(
	PGRAPHIC pGraphic,
	const FRAMEENTRY* frameEntry,
	int anchorX,
	int anchorY,
	XFORMTBL xform,
	int tbls );

void DrawShape(
	PGRAPHIC pGraphic,
	const SHAPEENTRY* shapeEntry,
	long shapeLength,
	long frameIndex,
	int anchorX,
	int anchorY );

bool HitTest(
	const FRAMEENTRY* frameEntry,
	int anchorX,
	int anchorY,
	int hitX,
	int hitY );

// Create a new frame by reflecting across a line running NW to SE.
char* CreateReflectShapeFrame(
	const FRAMEENTRY* frameEntry );


inline
PSHAPEENTRY GetShape( const char* shapeFile, int shapeIndex, long* shapeLength )
{
	PFLEXFILEHEADER header = (PFLEXFILEHEADER)shapeFile;
	if ( shapeIndex < header->count )
	{
		PFLEXFILEENTRY entry = (PFLEXFILEENTRY)(header+1) + shapeIndex;
		PSHAPEENTRY shapeEntry = (PSHAPEENTRY)(shapeFile + entry->offset);
		*shapeLength = entry->size;
		return shapeEntry;
	}
	*shapeLength = 0;
	return NULL;
}

inline
bool IsShapeTile( const SHAPEENTRY* shapeEntry, long shapeLength )
{
	return ( shapeLength != shapeEntry->size ); // tile
}

inline
int GetShapeFrameCount( const SHAPEENTRY* shapeEntry, long shapeLength )
{
	if ( shapeLength != shapeEntry->size ) // tile
		return shapeLength / PIXELS_PER_TILE;
	else
		return shapeEntry->offset[0]/sizeof(long) - 1;
}

inline
PFRAMEENTRY GetShapeFrame( const SHAPEENTRY* shapeEntry, long shapeLength, int frameIndex )
{
	if ( shapeLength == shapeEntry->size
		&& frameIndex < (int)(shapeEntry->offset[0]/sizeof(long)-1) )
	{
		return (PFRAMEENTRY)((char*)shapeEntry + shapeEntry->offset[frameIndex]);
	}
	ASSERT(FALSE);
	return NULL;
}

inline
TILE GetShapeTile( const SHAPEENTRY* shapeEntry, long shapeLength, int frameIndex )
{
	// something wrong in the chunk pattern 1843,1844
	// frameIndex will be greater than shapeLength / PIXELS_PER_TILE
	if ( shapeLength != shapeEntry->size )
	{
		//ASSERT( frameIndex < shapeLength / PIXELS_PER_TILE );
		return (TILE)((char*)shapeEntry + PIXELS_PER_TILE * frameIndex);
	}
	ASSERT(FALSE);
	return NULL;
}

inline
void GetShapeTileInfo( U7VECTOR2& hotspot, U7VECTOR2& dimension )
{
	hotspot.x = PIXELS_PER_TILE_IN_WIDTH - 1;
	hotspot.y = PIXELS_PER_TILE_IN_HEIGHT - 1;
	dimension.x = PIXELS_PER_TILE_IN_WIDTH;
	dimension.y = PIXELS_PER_TILE_IN_HEIGHT;
}

inline
void GetShapeFrameInfo( const FRAMEENTRY* frameEntry, U7VECTOR2& hotspot, U7VECTOR2& dimension )
{
	hotspot.x = frameEntry->leftX;
	hotspot.y = frameEntry->topY;
	dimension.x = frameEntry->leftX + 1 + frameEntry->rightX;
	dimension.y = frameEntry->topY + 1 + frameEntry->bottomY;
}

inline
void GetShapeFrameInfo( const char* shapeFile, int shapeType, int shapeFrame,
	U7VECTOR2& hotspot, U7VECTOR2& dimension )
{
	long shapeLength;
	PSHAPEENTRY shapeEntry = GetShape( shapeFile, shapeType, &shapeLength );
	GetShapeFrameInfo( shapeEntry, shapeLength, shapeFrame, hotspot, dimension );
}

inline
void DrawShape(
	PGRAPHIC pGraphic,
	const char* shapeFile,
	int shapeType,
	int shapeFrame,
	int anchorX,
	int anchorY )
{
	long shapeLength;
	PSHAPEENTRY shapeEntry = GetShape( shapeFile, shapeType, &shapeLength );
	DrawShape( pGraphic, shapeEntry, shapeLength, shapeFrame, anchorX, anchorY );
}

inline
void DrawShape(
	PGRAPHIC pGraphic,
	const char* shapeFile,
	const SHAPEID& shapeID,
	int anchorX,
	int anchorY )
{
	DrawShape( pGraphic, shapeFile, shapeID.shapeType, shapeID.shapeFrame, anchorX, anchorY );
}








/*
XFORM.TBL:    flex file with shape transform tables
  These are matrix used to transform the color of pixels that are seen
  through semi-transparent effect (glass, cloud, blood...)
  table     = 256 new_color (one for each possible color index)
  new_color = byte  (the new color index to use)

  There are 11 of these tables, and they're assigned to the
  17 translucent colors (0xee-0xfe) going backwards; i.e., table 0
  applies to color 0xfe, 1 to color 0xfd, 2 to 0xfc,... 16 to 0xee.
  When the renderer paints one of the translucent colors, it takes the
  pixel that's already in the frame buffer and looks it up in the
  appropriate xform table to get its replacement.
*/
inline
void CopyTranslucentLine( unsigned char* dst, unsigned char* src, int length, XFORMTBL xform, int tbls )
{
	const int first = 0xfe - tbls + 1;
	const int last  = 0xfe;

	while ( length-- > 0 )
	{
		unsigned char c = *src;
		if ( first <= c && c <= last )
		{
			c = xform[last-c][*dst];
		}
		
		*dst = c;

		dst++;
		src++;
	}
}

inline
void SetTranslucentLine( unsigned char* dst, unsigned char c, int length, XFORMTBL xform, int tbls )
{
	const int first = 0xfe - tbls + 1;
	const int last  = 0xfe;

	if ( first <= c && c <= last )
	{
		unsigned char* curXform = xform[last-c];
		while ( length-- > 0 )
		{
			*dst = curXform[*dst];
			dst++;
		}
	}
	else
	{
		memset( dst, c, length );
	}
}
